home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / deco.c < prev    next >
C/C++ Source or Header  |  1988-11-24  |  13KB  |  679 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: deco.c,v 2.3 84/07/19 11:45:12 guido Exp $";
  3.  
  4. /*
  5.  * B editor -- Delete and copy commands.
  6.  */
  7.  
  8. #include <ctype.h>
  9.  
  10. #include "b.h"
  11. #include "erro.h"
  12. #include "bobj.h"
  13. #include "node.h"
  14. #include "gram.h"
  15. #include "supr.h"
  16. #include "queu.h"
  17.  
  18.  
  19. value copyout(); /* Forward */
  20.  
  21. /*
  22.  * DELETE and COPY currently share a buffer, called the copy buffer.
  23.  * (Physically, there is one such a buffer in each environment.)
  24.  * In ordinary use, the copy buffer receives the text deleted by the
  25.  * last DELETE command (unless it just removed a hole); the COPY command
  26.  * can then be used (with the focus on a hole) to copy it back.
  27.  * When some portion of text must be held while other text is deleted,
  28.  * the COPY command again, but now with the focus on the text to be held,
  29.  * copies it to the buffer and deleted text won't overwrite the buffer
  30.  * until it is copied back at least once.
  31.  * If the buffer holds text that was explicitly copied out but not yet
  32.  * copied back in, it is saved on a file when the editor exits, so it can
  33.  * be used in the next session; but this is not true for text implicitly
  34.  * placed in the buffer through DELETE.
  35.  */
  36.  
  37. /*
  38.  * Delete command -- delete the text in the focus, or delete the hole
  39.  * if it is only a hole.
  40.  */
  41.  
  42. Visible bool
  43. delete(ep)
  44.     register environ *ep;
  45. {
  46.     higher(ep);
  47.     shrink(ep);
  48.     if (ishole(ep))
  49.         return delhole(ep);
  50.     if (!ep->copyflag) {
  51.         release(ep->copybuffer);
  52.         ep->copybuffer = copyout(ep);
  53.     }
  54.     return delbody(ep);
  55. }
  56.  
  57.  
  58. /*
  59.  * Delete the focus under the assumption that it contains some text.
  60.  */
  61.  
  62. Visible bool
  63. delbody(ep)
  64.     register environ *ep;
  65. {
  66.     ep->changed = Yes;
  67.  
  68.     subgrow(ep, No); /* Don't ignore spaces */
  69.     switch (ep->mode) {
  70.  
  71.     case SUBRANGE:
  72.         if (ep->s1&1)
  73.             return delfixed(ep);
  74.         return delvarying(ep);
  75.  
  76.     case SUBSET:
  77.         return delsubset(ep, Yes);
  78.  
  79.     case SUBLIST:
  80.         return delsublist(ep);
  81.  
  82.     case WHOLE:
  83.         return delwhole(ep);
  84.  
  85.     default:
  86.         Abort();
  87.         /* NOTREACHED */
  88.     }
  89. }
  90.  
  91.  
  92. /*
  93.  * Delete portion (ep->mode == SUBRANGE) of varying text ((ep->s1&1) == 0).
  94.  */
  95.  
  96. Hidden bool
  97. delvarying(ep)
  98.     register environ *ep;
  99. {
  100.     auto queue q = Qnil;
  101.     register node n = tree(ep->focus);
  102.     auto value v = (value) child(n, ep->s1/2);
  103.     register len = Length(v);
  104.  
  105.     Assert(ep->mode == SUBRANGE && !(ep->s1&1)); /* Wrong call */
  106.     Assert(Type(v) == Tex); /* Inconsistent parse tree */
  107.     if (ep->s2 == 0
  108.         && !mayinsert(tree(ep->focus), ep->s1/2, 0, Str(v)[ep->s3 + 1])) {
  109.         /* Cannot do simple substring deletion. */
  110.         stringtoqueue(Str(v) + ep->s3 + 1, &q);
  111.         delfocus(&ep->focus);
  112.         ep->mode = WHOLE;
  113.         return app_queue(ep, &q);
  114.     }
  115.     v = copy(v);
  116.     putintrim(&v, ep->s2, len - ep->s3 - 1, "");
  117.     s_downi(ep, ep->s1/2);
  118.     replace(&ep->focus, (node) v);
  119.     s_up(ep);
  120.     ep->mode = VHOLE;
  121.     return Yes;
  122. }
  123.  
  124.  
  125. /*
  126.  * Delete portion (ep->mode == SUBRANGE) of fixed text ((ep->s1&1) == 1).
  127.  */
  128.  
  129. Hidden bool
  130. delfixed(ep)
  131.     register environ *ep;
  132. {
  133.     register node n = tree(ep->focus);
  134.     char buf[15]; /* Long enough for all fixed texts */
  135.     register string repr = noderepr(n)[ep->s1/2];
  136.     register int len;
  137.     queue q = Qnil;
  138.     bool ok;
  139.  
  140.     Assert(ep->mode == SUBRANGE && (ep->s1&1));
  141.     if (ep->s1 > 1) {
  142.         ep->mode = FHOLE;
  143.         return Yes;
  144.     }
  145.     Assert(fwidth(repr) < sizeof buf - 1);
  146.     len = ep->s2;
  147.     ep->s2 = ep->s3 + 1;
  148.     ep->mode = FHOLE;
  149.     nosuggtoqueue(ep, &q);
  150.     strcpy(buf, repr);
  151.     if (nchildren(tree(ep->focus)) > 0)
  152.         buf[len] = 0;
  153.     else
  154.         strcpy(buf+len, buf+ep->s2);
  155.     delfocus(&ep->focus);
  156.     ep->mode = WHOLE;
  157.     markpath(&ep->focus, 1);
  158.     ok = ins_string(ep, buf, &q, 0);
  159.     if (!ok) {
  160.         qrelease(q);
  161.         return No;
  162.     }
  163.     firstmarked(&ep->focus, 1) || Abort();
  164.     unmkpath(&ep->focus, 1);
  165.     fixfocus(ep, len);
  166.     return app_queue(ep, &q);
  167. }
  168.  
  169.  
  170. /*
  171.  * Delete focus if ep->mode == SUBSET.
  172.  */
  173.  
  174. Hidden bool
  175. delsubset(ep, hack)
  176.     register environ *ep;
  177.     bool hack;
  178. {
  179.     auto queue q = Qnil;
  180.     auto queue q2 = Qnil;
  181.     register node n = tree(ep->focus);
  182.     register node nn;
  183.     register string *rp = noderepr(n);
  184.     register int nch = nchildren(n);
  185.     register int i;
  186.  
  187.     if (hack) {
  188.         shrsubset(ep);
  189.         if (ep->s1 == ep->s2 && !(ep->s1&1)) {
  190.             nn = child(tree(ep->focus), ep->s1/2);
  191.             if (fwidth(noderepr(nn)[0]) < 0) {
  192.                 /* It starts with a newline, leave the newline */
  193.                 s_downi(ep, ep->s1/2);
  194.                 ep->mode = SUBSET;
  195.                 ep->s1 = 2;
  196.                 ep->s2 = 2*nchildren(nn) + 1;
  197.                 return delsubset(ep, hack);
  198.             }
  199.         }
  200.         subgrsubset(ep, No); /* Undo shrsubset */
  201.         if (ep->s2 == 3 && rp[1] && Strequ(rp[1], "\t"))
  202.             --ep->s2; /* Hack for deletion of unit-head or if/for/wh. head */
  203.     }
  204.     if (ep->s1 == 1 && Fw_negative(rp[0]))
  205.         ++ep->s1; /* Hack for deletion of test-suite or refinement head */
  206.  
  207.     if (Fw_zero(rp[0]) ? (ep->s2 < 3 || ep->s1 > 3) : ep->s1 > 1) {
  208.         /* No deep structural change */
  209.         for (i = (ep->s1+1)/2; i <= ep->s2/2; ++i) {
  210.             s_downi(ep, i);
  211.             delfocus(&ep->focus);
  212.             s_up(ep);
  213.         }
  214.         if (ep->s1&1) {
  215.             ep->mode = FHOLE;
  216.             ep->s2 = 0;
  217.         }
  218.         else if (Type(child(tree(ep->focus), ep->s1/2)) == Tex) {
  219.             ep->mode = VHOLE;
  220.             ep->s2 = 0;
  221.         }
  222.         else {
  223.             s_downi(ep, ep->s1/2);
  224.             ep->mode = ATBEGIN;
  225.         }
  226.         return Yes;
  227.     }
  228.  
  229.     balance(ep); /* Make balanced \t - \b pairs */
  230.     subsettoqueue(n, 1, ep->s1-1, &q);
  231.     subsettoqueue(n, ep->s2+1, 2*nch+1, &q2);
  232.     nonewline(&q2); /* Wonder what will happen...? */
  233.     delfocus(&ep->focus);
  234.     ep->mode = ATBEGIN;
  235.     leftvhole(ep);
  236.     if (!ins_queue(ep, &q, &q2)) {
  237.         qrelease(q2);
  238.         return No;
  239.     }
  240.     return app_queue(ep, &q2);
  241. }
  242.  
  243.  
  244. /*
  245.  * Delete the focus if ep->mode == SUBLIST.
  246.  */
  247.  
  248. delsublist(ep)
  249.     register environ *ep;
  250. {
  251.     register node n;
  252.     register int i;
  253.     register int sym;
  254.     queue q = Qnil;
  255.     bool flag;
  256.  
  257.     Assert(ep->mode == SUBLIST);
  258.     n = tree(ep->focus);
  259.     flag = fwidth(noderepr(n)[0]) < 0;
  260.     for (i = ep->s3; i > 0; --i) {
  261.         n = lastchild(n);
  262.         Assert(n);
  263.     }
  264.     if (flag) {
  265.         n = nodecopy(n);
  266.         s_down(ep);
  267.         do {
  268.             delfocus(&ep->focus);
  269.         } while (rite(&ep->focus));
  270.         if (!allowed(ep->focus, symbol(n))) {
  271.             error(DEL_REM); /* The remains wouldn't fit */
  272.             noderelease(n);
  273.             return No;
  274.         }
  275.         replace(&ep->focus, n);
  276.         s_up(ep);
  277.         s_down(ep); /* I.e., to leftmost sibling */
  278.         ep->mode = WHOLE;
  279.         return Yes;
  280.     }
  281.     sym = symbol(n);
  282.     if (sym == Optional || sym == Hole) {
  283.         delfocus(&ep->focus);
  284.         ep->mode = WHOLE;
  285.     }
  286.     else if (!allowed(ep->focus, sym)) {
  287.         preptoqueue(n, &q);
  288.         delfocus(&ep->focus);
  289.         ep->mode = WHOLE;
  290.         return app_queue(ep, &q);
  291.     }
  292.     else {
  293.         replace(&ep->focus, nodecopy(n));
  294.         ep->mode = ATBEGIN;
  295.     }
  296.     return Yes;
  297. }
  298.  
  299.  
  300. /*
  301.  * Delete the focus if ep->mode == WHOLE.
  302.  */
  303.  
  304. Hidden bool
  305. delwhole(ep)
  306.     register environ *ep;
  307. {
  308.     register int sym = symbol(tree(ep->focus));
  309.  
  310.     Assert(ep->mode == WHOLE);
  311.     if (sym == Optional || sym == Hole)
  312.         return No;
  313.     delfocus(&ep->focus);
  314.     return Yes;
  315. }
  316.  
  317.  
  318. /*
  319.  * Delete the focus if it is only a hole.
  320.  * Assume shrink() has been called before!
  321.  */
  322.  
  323. Hidden bool
  324. delhole(ep)
  325.     register environ *ep;
  326. {
  327.     node n;
  328.     int sym;
  329.     bool flag = No;
  330.  
  331.     switch (ep->mode) {
  332.     
  333.     case ATBEGIN:
  334.     case VHOLE:
  335.     case FHOLE:
  336.     case ATEND:
  337.         return widen(ep);
  338.  
  339.     case WHOLE:
  340.         Assert((sym = symbol(tree(ep->focus))) == Optional || sym == Hole);
  341.         if (ichild(ep->focus) != 1)
  342.             break;
  343.         if (!up(&ep->focus))
  344.             return No;
  345.         higher(ep);
  346.         ep->mode = SUBSET;
  347.         ep->s1 = 2;
  348.         ep->s2 = 2;
  349.         if (fwidth(noderepr(tree(ep->focus))[0]) < 0) {
  350.             flag = Yes;
  351.             ep->s2 = 3; /* Extend to rest of line */
  352.         }
  353.     }
  354.  
  355.     ep->changed = Yes;
  356.     grow(ep);
  357.  
  358.     switch (ep->mode) {
  359.  
  360.     case SUBSET:
  361.         if (!delsubset(ep, No))
  362.             return No;
  363.         if (!flag)
  364.             return widen(ep);
  365.         leftvhole(ep);
  366.         oneline(ep);
  367.         return Yes;
  368.  
  369.     case SUBLIST:
  370.         n = tree(ep->focus);
  371.         n = lastchild(n);
  372.         sym = symbol(n);
  373.         if (!allowed(ep->focus, sym)) {
  374.             error(DEL_REM); /* The remains wouldn't fit */
  375.             return No;
  376.         }
  377.         flag = samelevel(sym, symbol(tree(ep->focus)));
  378.         replace(&ep->focus, nodecopy(n));
  379.         if (flag) {
  380.             ep->mode = SUBLIST;
  381.             ep->s3 = 1;
  382.         }
  383.         else
  384.             ep->mode = WHOLE;
  385.         return Yes;
  386.  
  387.     case WHOLE:
  388.         Assert(!parent(ep->focus)); /* Must be at root! */
  389.         return No;
  390.  
  391.     default:
  392.         Abort();
  393.         /* NOTREACHED */
  394.  
  395.     }
  396. }
  397.  
  398.  
  399. /*
  400.  * Subroutine to delete the focus.
  401.  */
  402.  
  403. Visible Procedure
  404. delfocus(pp)
  405.     register path *pp;
  406. {
  407.     register path pa = parent(*pp);
  408.     register int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
  409.  
  410.     replace(pp, child(gram(sympa), ichild(*pp)));
  411. }
  412.  
  413.  
  414. /*
  415.  * Copy command -- copy the focus to the copy buffer if it contains
  416.  * some text, copy the copy buffer into the focus if the focus is
  417.  * empty (just a hole).
  418.  */
  419.  
  420. Visible bool
  421. copyinout(ep)
  422.     register environ *ep;
  423. {
  424.     shrink(ep);
  425.     if (!ishole(ep)) {
  426.         release(ep->copybuffer);
  427.         ep->copybuffer = copyout(ep);
  428.         ep->copyflag = !!ep->copybuffer;
  429.         return ep->copyflag;
  430.     }
  431.     else {
  432.         fixit(ep); /* Make sure it looks like a hole now */
  433.         if (!copyin(ep, (queue) ep->copybuffer))
  434.             return No;
  435.         ep->copyflag = No;
  436.         return Yes;
  437.     }
  438. }
  439.  
  440.  
  441. /*
  442.  * Copy the focus to the copy buffer.
  443.  */
  444.  
  445. Visible value
  446. copyout(ep)
  447.     register environ *ep;
  448. {
  449.     auto queue q = Qnil;
  450.     auto path p;
  451.     register node n;
  452.     register value v;
  453.     char buf[15];
  454.     register string *rp;
  455.     register int i;
  456.  
  457.     switch (ep->mode) {
  458.     case WHOLE:
  459.         preptoqueue(tree(ep->focus), &q);
  460.         break;
  461.     case SUBLIST:
  462.         p = pathcopy(ep->focus);
  463.         for (i = ep->s3; i > 0; --i)
  464.             downrite(&p) || Abort();
  465.         for (i = ep->s3; i > 0; --i) {
  466.             up(&p) || Abort();
  467.             n = tree(p);
  468.             subsettoqueue(n, 1, 2*nchildren(n) - 1, &q);
  469.         }
  470.         pathrelease(p);
  471.         break;
  472.     case SUBSET:
  473.         balance(ep);
  474.         subsettoqueue(tree(ep->focus), ep->s1, ep->s2, &q);
  475.         break;
  476.     case SUBRANGE:
  477.         Assert(ep->s3 >= ep->s2);
  478.         if (ep->s1&1) { /* Fixed text */
  479.             Assert(ep->s3 - ep->s2 + 1 < sizeof buf);
  480.             rp = noderepr(tree(ep->focus));
  481.             Assert(ep->s2 < Fwidth(rp[ep->s1/2]));
  482.             strncpy(buf, rp[ep->s1/2] + ep->s2, ep->s3 - ep->s2 + 1);
  483.             buf[ep->s3 - ep->s2 + 1] = 0;
  484.             stringtoqueue(buf, &q);
  485.         }
  486.         else { /* Varying text */
  487.             v = (value) child(tree(ep->focus), ep->s1/2);
  488.             Assert(Type(v) == Tex);
  489.             v = trim(v, ep->s2, Length(v) - ep->s3 - 1);
  490.             preptoqueue((node)v, &q);
  491.             release(v);
  492.         }
  493.         break;
  494.     default:
  495.         Abort();
  496.     }
  497.     nonewline(&q);
  498.     return (value)q;
  499. }
  500.  
  501.  
  502. /*
  503.  * Subroutine to ensure the copy buffer doesn't start with a newline.
  504.  */
  505.  
  506. Hidden Procedure
  507. nonewline(pq)
  508.     register queue *pq;
  509. {
  510.     register node n;
  511.     register int c;
  512.  
  513.     if (!emptyqueue(*pq)) {
  514.         for (;;) {
  515.             n = queuebehead(pq);
  516.             if (Type(n) == Tex) {
  517.                 if (Str((value) n)[0] != '\n')
  518.                     preptoqueue(n, pq);
  519.                 noderelease(n);
  520.                 break;
  521.             }
  522.             else {
  523.                 c = nodechar(n);
  524.                 if (c != '\n')
  525.                     preptoqueue(n, pq);
  526.                 else
  527.                     splitnode(n, pq);
  528.                 noderelease(n);
  529.                 if (c != '\n')
  530.                     break;
  531.             }
  532.         }
  533.     }
  534. }
  535.  
  536.  
  537. /*
  538.  * Refinement for copyout, case SUBSET: make sure that \t is balanced with \b.
  539.  * Actually it can only handle the case where a \t is in the subset and the
  540.  * matching \b is immediately following.
  541.  */
  542.  
  543. Hidden Procedure
  544. balance(ep)
  545.     environ *ep;
  546. {
  547.     string *rp = noderepr(tree(ep->focus));
  548.     int i;
  549.     int level = 0;
  550.  
  551.     Assert(ep->mode == SUBSET);
  552.     for (i = ep->s1/2; i*2 < ep->s2; ++i) {
  553.         if (rp[i]) {
  554.             if (index(rp[i], '\t'))
  555.                 ++level;
  556.             else if (index(rp[i], '\b'))
  557.                 --level;
  558.         }
  559.     }
  560.     if (level > 0 && i*2 == ep->s2 && rp[i] && index(rp[i], '\b'))
  561.         ep->s2 = 2*i + 1;
  562. }
  563.  
  564.  
  565. /*
  566.  * Copy the copy buffer to the focus.
  567.  */
  568.  
  569. Hidden bool
  570. copyin(ep, q)
  571.     register environ *ep;
  572.     /*auto*/ queue q;
  573. {
  574.     auto queue q2 = Qnil;
  575.  
  576.     if (!q) {
  577.         error(COPY_EMPTY); /* Empty copy buffer */
  578.         return No;
  579.     }
  580.     ep->changed = Yes;
  581.     q = qcopy(q);
  582.     if (!ins_queue(ep, &q, &q2)) {
  583.         qrelease(q2);
  584.         return No;
  585.     }
  586.     return app_queue(ep, &q2);
  587. }
  588.  
  589.  
  590. /*
  591.  * Find out whether the focus looks like a hole or if it has some real
  592.  * text in it.
  593.  * Assumes shrink(ep) has already been performed.
  594.  */
  595.  
  596. Visible bool
  597. ishole(ep)
  598.     register environ *ep;
  599. {
  600.     register int sym;
  601.  
  602.     switch (ep->mode) {
  603.     
  604.     case ATBEGIN:
  605.     case ATEND:
  606.     case VHOLE:
  607.     case FHOLE:
  608.         return Yes;
  609.  
  610.     case SUBLIST:
  611.     case SUBRANGE:
  612.         return No;
  613.  
  614.     case SUBSET:
  615.         return colonhack(ep); /* (Side-effect!) */
  616.  
  617.     case WHOLE:
  618.         sym = symbol(tree(ep->focus));
  619.         return sym == Optional || sym == Hole;
  620.  
  621.     default:
  622.         Abort();
  623.         /* NOTREACHED */
  624.     }
  625. }
  626.  
  627.  
  628. /*
  629.  * Amendment to ishole so that it categorizes '?: ?' as a hole.
  630.  * This makes deletion of empty refinements / alternative-suites
  631.  * easier (Steven).
  632.  */
  633.  
  634. Hidden bool
  635. colonhack(ep)
  636.     environ *ep;
  637. {
  638.     node n = tree(ep->focus);
  639.     node n1;
  640.     string *rp = noderepr(n);
  641.     int i;
  642.     int sym;
  643.  
  644.     for (i = ep->s1; i <= ep->s2; ++i) {
  645.         if (i&1) {
  646.             if (!allright(rp[i/2]))
  647.                 return No;
  648.         }
  649.         else {
  650.             n1 = child(n, i/2);
  651.             if (Type(n1) == Tex)
  652.                 return No;
  653.             sym = symbol(n1);
  654.             if (sym != Hole && sym != Optional)
  655.                 return No;
  656.         }
  657.     }
  658.     return Yes;
  659. }
  660.  
  661.  
  662. /*
  663.  * Refinement for colonhack.  Recognize strings that are almost blank
  664.  * (i.e. containing only spaces, colons and the allowed control characters).
  665.  */
  666.  
  667. Hidden bool
  668. allright(repr)
  669.     string repr;
  670. {
  671.     if (repr) {
  672.         for (; *repr; ++repr) {
  673.             if (!index(": \t\b\n\r", *repr))
  674.                 return No;
  675.         }
  676.     }
  677.     return Yes;
  678. }
  679.